﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Xaml.Behaviors;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace WPF_Test.Behaviors
{
    /// <summary>
    /// Class ScrollViewerExtend.
    /// </summary>
    [Obsolete]
    public class ItemsControlBehavior : Behavior<ItemsControl>
    {
        #region Public 字段

        /// <summary>
        /// The is enable manipulation boundary feedback property
        /// </summary>
        public static readonly DependencyProperty IsEnableManipulationBoundaryFeedbackProperty =
            DependencyProperty.Register("IsEnableManipulationBoundaryFeedback", typeof(bool), typeof(ItemsControlBehavior), new PropertyMetadata(false, OnIsEnableManipulationBoundaryFeedbackPropertyChanged));

        /// <summary>
        /// The is horizontal roll property
        /// </summary>
        public static readonly DependencyProperty IsHorizontalRollProperty =
            DependencyProperty.Register("IsHorizontalRoll", typeof(bool), typeof(ItemsControlBehavior), new PropertyMetadata(false, OnIsHorizontalRollPropertyChanged));

        /// <summary>
        /// The roll bottom command property
        /// </summary>
        public static readonly DependencyProperty RollBottomCommandProperty =
            DependencyProperty.Register("RollBottomCommand", typeof(ICommand), typeof(ItemsControlBehavior), new PropertyMetadata(null, OnRollBottomCommandPropertyChanged));

        /// <summary>
        /// The scroll to item index property
        /// </summary>
        public static readonly DependencyProperty ScrollToItemIndexProperty =
            DependencyProperty.Register("ScrollToItemIndex", typeof(int), typeof(ItemsControlBehavior), new PropertyMetadata(-1, OnScrollToItemIndexPropertyChanged));

        /// <summary>
        /// The vertical offset ex property
        /// </summary>
        public static readonly DependencyProperty VerticalOffsetExProperty =
            DependencyProperty.Register("VerticalOffsetEx", typeof(double), typeof(ItemsControlBehavior), new PropertyMetadata(0.0, OnVerticalOffsetExChanged));

        /// <summary>
        /// The date time
        /// </summary>
        public DateTime dateTime = DateTime.Now;

        #endregion Public 字段

        #region Private 字段

        /// <summary>
        /// The items control
        /// </summary>
        private ItemsControl itemsControl;

        /// <summary>
        /// The scroll viewer
        /// </summary>
        private ScrollViewer scrollViewer;

        #endregion Private 字段

        #region Public 属性

        /// <summary>
        /// Gets or sets a value indicating whether this instance is enable manipulation boundary feedback.
        /// </summary>
        /// <value><c>true</c> if this instance is enable manipulation boundary feedback; otherwise, <c>false</c>.</value>
        public bool IsEnableManipulationBoundaryFeedback
        {
            get { return (bool)GetValue(IsEnableManipulationBoundaryFeedbackProperty); }
            set { SetValue(IsEnableManipulationBoundaryFeedbackProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is horizontal roll.
        /// </summary>
        /// <value><c>true</c> if this instance is horizontal roll; otherwise, <c>false</c>.</value>
        public bool IsHorizontalRoll
        {
            get { return (bool)GetValue(IsHorizontalRollProperty); }
            set { SetValue(IsHorizontalRollProperty, value); }
        }

        /// <summary>
        /// Gets or sets the roll bottom command.
        /// </summary>
        /// <value>The roll bottom command.</value>
        public ICommand RollBottomCommand
        {
            get { return (ICommand)GetValue(RollBottomCommandProperty); }
            set { SetValue(RollBottomCommandProperty, value); }
        }

        /// <summary>
        /// Gets or sets the index of the scroll to item.
        /// </summary>
        /// <value>The index of the scroll to item.</value>
        public int ScrollToItemIndex
        {
            get { return (int)GetValue(ScrollToItemIndexProperty); }
            set { SetValue(ScrollToItemIndexProperty, value); }
        }

        /// <summary>
        /// Gets or sets the vertical offset ex.
        /// </summary>
        /// <value>The vertical offset ex.</value>
        public double VerticalOffsetEx
        {
            get { return (double)GetValue(VerticalOffsetExProperty); }
            set { SetValue(VerticalOffsetExProperty, value); }
        }

        #endregion Public 属性

        #region Protected 方法

        /// <summary>
        /// 在行为附加到 AssociatedObject 后调用。
        /// </summary>
        /// <remarks>替代它以便将功能挂钩到 AssociatedObject。</remarks>
        protected override void OnAttached()
        {
            base.OnAttached();
            itemsControl = AssociatedObject;
            SetIsEnableManipulationBoundaryFeedbackProperty();
            SetIsHorizontalRollProperty();
            SetRollBottomCommand();
        }

        #endregion Protected 方法

        #region Private 方法

        /// <summary>
        /// Handles the <see cref="E:IsEnableManipulationBoundaryFeedbackPropertyChanged" /> event.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
        private static void OnIsEnableManipulationBoundaryFeedbackPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sc = d as ItemsControlBehavior;
            sc.SetIsEnableManipulationBoundaryFeedbackProperty();
        }

        /// <summary>
        /// Handles the <see cref="E:IsHorizontalRollPropertyChanged" /> event.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
        private static void OnIsHorizontalRollPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sc = d as ItemsControlBehavior;
            sc.SetIsHorizontalRollProperty();
        }

        /// <summary>
        /// Handles the <see cref="E:RollBottomCommandPropertyChanged" /> event.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs" /> instance containing the event data.</param>
        private static void OnRollBottomCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var sc = d as ItemsControlBehavior;
            sc.SetRollBottomCommand();
        }

        /// <summary>
        /// Handles the <see cref="E:ScrollToItemIndexPropertyChanged" /> event.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnScrollToItemIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ice = (ItemsControlBehavior)d;
            ice.ScrollToSelection((int)e.NewValue);
        }

        /// <summary>
        /// Handles the <see cref="E:VerticalOffsetExChanged" /> event.
        /// </summary>
        /// <param name="d">The d.</param>
        /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnVerticalOffsetExChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ice = d as ItemsControlBehavior;
            ice.scrollViewer.ScrollToVerticalOffset((double)e.NewValue);
        }

        /// <summary>
        /// Handles the PreviewMouseWheel event of the Scr control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="MouseWheelEventArgs" /> instance containing the event data.</param>
        private static void Scr_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            ScrollViewer scrollViewer = sender as ScrollViewer;
            if (e.Delta > 0)
                scrollViewer.LineLeft();
            else
                scrollViewer.LineRight();
            e.Handled = true;
        }

        /// <summary>
        /// Handles the Loaded1 event of the ItemsControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
        private void ItemsControl_Loaded(object sender, RoutedEventArgs e)
        {
            var scr = itemsControl.GetChildObject<ScrollViewer>();
            if (scr != null)
            {
                if (IsHorizontalRoll)
                {
                    scr.PreviewMouseWheel += Scr_PreviewMouseWheel;
                }
                else
                {
                    scr.PreviewMouseWheel -= Scr_PreviewMouseWheel;
                }
            }
        }

        /// <summary>
        /// Handles the Loaded1 event of the ItemsControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RoutedEventArgs" /> instance containing the event data.</param>
        private void ItemsControl_Loaded1(object sender, RoutedEventArgs e)
        {
            scrollViewer = itemsControl.GetChildObject<ScrollViewer>();
            if (scrollViewer != null)
            {
                scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged;
                scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
            }
            itemsControl.PreviewMouseWheel += (sender1, e1) =>
            {
                if (scrollViewer == null)
                {
                    scrollViewer = itemsControl.GetChildObject<ScrollViewer>();
                    if (scrollViewer != null)
                    {
                        scrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged;
                        scrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
                    }
                }
            };
        }

        /// <summary>
        /// 滚动至指定Item
        /// </summary>
        /// <param name="index">The index.</param>
        private void ScrollToSelection(int index)
        {
            var vector = VisualTreeHelper.GetOffset((Visual)itemsControl.Items[index]);
            DoubleAnimation doubleAnimation = new DoubleAnimation(scrollViewer.VerticalOffset, vector.Y, new Duration(TimeSpan.FromMilliseconds(500)));
            BeginAnimation(VerticalOffsetExProperty, doubleAnimation);
        }

        /// <summary>
        /// Handles the ScrollChanged event of the ScrollViewer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="ScrollChangedEventArgs" /> instance containing the event data.</param>
        private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            var viewer = sender as ScrollViewer;
            if (viewer.IsVerticalScrollBarAtButtom() && (DateTime.Now - dateTime).TotalMilliseconds > 300)
            {
                if (RollBottomCommand != null)
                {
                    RollBottomCommand.Execute(viewer);
                }
                dateTime = DateTime.Now;
            }
        }

        /// <summary>
        /// Sets the is enable manipulation boundary feedback property.
        /// </summary>
        private void SetIsEnableManipulationBoundaryFeedbackProperty()
        {
            if (IsEnableManipulationBoundaryFeedback)
            {
                itemsControl.ManipulationBoundaryFeedback += UIElement_ManipulationBoundaryFeedback;
            }
            else
            {
                itemsControl.ManipulationBoundaryFeedback -= UIElement_ManipulationBoundaryFeedback;
            }
        }

        /// <summary>
        /// Sets the is horizontal roll property.
        /// </summary>
        private void SetIsHorizontalRollProperty()
        {
            if (itemsControl == null)
            {
                return;
            }
            itemsControl.Loaded -= ItemsControl_Loaded;
            itemsControl.Loaded += ItemsControl_Loaded;
        }

        /// <summary>
        /// Sets the roll bottom command.
        /// </summary>
        private void SetRollBottomCommand()
        {
            if (itemsControl == null)
            {
                return;
            }
            itemsControl.Loaded -= ItemsControl_Loaded1;
            itemsControl.Loaded += ItemsControl_Loaded1;
        }

        /// <summary>
        /// Handles the ManipulationBoundaryFeedback event of the UIElement control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ManipulationBoundaryFeedbackEventArgs" /> instance containing the event data.</param>
        private void UIElement_ManipulationBoundaryFeedback(object sender, System.Windows.Input.ManipulationBoundaryFeedbackEventArgs e)
        {
            e.Handled = true;
        }

        #endregion Private 方法
    }
}